﻿using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

namespace winS.UnityEditor.UIElement
{
    public class DropdownField : EditorField<string>
    {
        /// <summary>
        /// 当前值是否无效.
        /// 如果 <see cref="choiceList"/> 未包含当前值, 则返回 true
        /// </summary>
        public bool isInvalidValue { get; private set; }
        public int index { get => _index; set => SetIndex(value); }

        public IList<string> choiceList { get => _choiceList; set => SetChoiceList(value); }
        public ReadonlyText readonlyText { get; private set; }
        public EditorElement dropdownBox { get; private set; }

        private int _index;
        private Icon warningIcon;
        private IList<string> _choiceList;
        private DropdownMenu dropdownMenu;

        internal DropdownField(ElementFactory elementFactory) : base(elementFactory)
        {
            Add(dropdownBox = EditorElementUtility.elementFactory.CreateRow(1f));
            dropdownBox.style.paddingRight = 4f;
            dropdownBox.style.paddingLeft = 2f;
            dropdownBox.style.overflow = Overflow.Hidden;
            dropdownBox.style.SetBackgroundColor(88, 88, 88);
            dropdownBox.style.SetBorder(elementFactory.borderColor, 1f, 2f);
            dropdownBox.RegisterCallback<ClickEvent>(ClickCallback);
            dropdownBox.RegisterCallback<MouseDownEvent>(MouseDownCallback);
            EditorElementUtility.ApplyFocusElementStyle(dropdownBox, elementFactory.borderColor);

            dropdownBox.Add(readonlyText = EditorElementUtility.elementFactory.CreateReadonlyText(false, false));
            EditorElementUtility.ApplySubFieldStyle(readonlyText);
            readonlyText.pickingMode = PickingMode.Ignore;
            readonlyText.style.paddingBottom = 1f;

            Icon arrowIcon = EditorElementUtility.elementFactory.CreateIcon(PackageAssets.Icons.arrowDown, 12f, elementFactory.softWhiteColor);
            arrowIcon.pickingMode = PickingMode.Ignore;
            dropdownBox.Add(arrowIcon);
        }

        public void Refresh()
        {
            dropdownMenu?.Refresh();
        }

        public override void SetValueWithoutNotify(string value)
        {
            readonlyText.text = value;
            CheckValueValidity(value);
            base.SetValueWithoutNotify(value);
        }

        public void SetIndexWithoutNotify(int newIndex)
        {
            _index = newIndex;
            SetValueWithoutNotify(choiceList == null || choiceList.Count <= newIndex || newIndex < 0 ? null : choiceList[newIndex]);
        }

        protected override void SetValue(string value)
        {
            readonlyText.text = value;
            CheckValueValidity(value);
            base.SetValue(value);
        }

        private void CheckValueValidity(string value)
        {
            _index = (choiceList == null || choiceList.Count == 0) ? -1 : choiceList.IndexOf(value);
            if (_index != -1)
            {
                if (isInvalidValue)
                {
                    dropdownBox.Remove(warningIcon);
                    isInvalidValue = false;
                }
                return;
            }
            isInvalidValue = true;
            warningIcon ??= EditorElementUtility.elementFactory.CreateIconWithName("无效值警告图标", PackageAssets.Icons.warnning, 16f, new Color32(183, 46, 46, 255));
            dropdownBox.Insert(1, warningIcon);
        }
        private void SetIndex(int newIndex)
        {
            if (_index == newIndex) return;
            _index = newIndex;
            value = choiceList == null || choiceList.Count <= newIndex || newIndex < 0 ? null : choiceList[newIndex];
        }
        private void SetChoiceList(IList<string> newChoiceList)
        {
            _choiceList = newChoiceList;
            dropdownMenu?.SetData(newChoiceList);
            CheckValueValidity(value);
        }
        private void ClickCallback(ClickEvent clickEvent)
        {
            if (choiceList == null) return;
            dropdownMenu ??= new DropdownMenu(_choiceList, newValue =>
            {
                if (value == newValue) return;
                value = newValue;
            }, 14f);
            dropdownMenu.Show(dropdownBox);
        }
        private void MouseDownCallback(MouseDownEvent mouseDownEvent)
        {
            mouseDownEvent.StopPropagation();
        }
    }
}